package com.rankeiot.platform.service;

import cn.hutool.core.date.DateUtil;
import com.aliyun.oss.*;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.rankeiot.core.config.ConfigManager;
import com.rankeiot.core.config.ControlType;
import com.rankeiot.core.config.IConfigItem;
import com.rankeiot.core.config.Item;
import com.rankeiot.core.data.response.Resp;
import com.rankeiot.core.exception.BusinessException;
import com.rankeiot.core.util.IDUtil;
import com.rankeiot.core.util.StringUtil;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.event.EventListener;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
//@ConditionalOnMissingBean(AliyunOssFileStorage.class)
@ConditionalOnClass(name = "com.aliyun.oss.OSS")
public class AliyunOssFileStorage implements IFileStoreService{
    public enum AliyunConfig implements IConfigItem{
        @Item(title="accessKey")
        accessKey,
        @Item(title="secretKey")
        secretKey,
        @Item(title="endPoint")
        endPoint,
        @Item(title="bucketName")
        bucketName,
        @Item(title="domain")
        domain,
        @Item(title="基础路径",defaultValue = "public/")
        basePath,
        @Item(title="签名保护",type = ControlType.Switch,memo = "是否需要签名保护")
        signed,
        @Item(title="客户端直传",type = ControlType.Switch,memo = "是否开启客户端直传",front = true)
        clientDirect
    }
    private final String suffix="files/oss/";
    private final Pattern suffixMatcher= Pattern.compile("^/?"+suffix);
    private final Pattern fullPathMatcher = Pattern.compile("^https?://");
    @Value("${files.path:files}")
    private String filesPath;
    LocalFileStoreService local;
    @PostConstruct
    public void init(){
        ConfigManager.register("存储-阿里云",AliyunConfig.class);

       // client=new OSSClientBuilder().build(AliyunConfig.endPoint.strValue(),AliyunConfig.accessKey.strValue(),AliyunConfig.secretKey.strValue());
    }
    private OSS createClient(){
       return new OSSClientBuilder().build(AliyunConfig.endPoint.strValue(),AliyunConfig.accessKey.strValue(),AliyunConfig.secretKey.strValue());
    }
//    @EventListener
//    public void onConfigChange(ConfigServiceImpl.ConfigChangeEvent event){
//        //event.getKey()
//        AliyunConfig.values();
//        //client.en
//    }
    @Override
    public Resp<String> save(InputStream file, String fileName, String user) throws IOException {
       // client.putBucketImage()
        String extension = fileName;
        int idx = extension.lastIndexOf('.');
        if (idx > 0) {
            extension = extension.substring(idx);
        } else {
            extension = ".unknown";
        }
        String path=user+"/"+ IDUtil.getUUID()+extension;
        OSS ossClient=createClient();
        try {
            ossClient.putObject(AliyunConfig.bucketName.strValue(), AliyunConfig.basePath.strValue() + path, file);
        } catch (OSSException oe) {
            Resp.fail(oe.getMessage());
        }finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return Resp.of(suffix+path);
    }

    @Override
    public Resp delete(String path, String user) {
        if(!path.startsWith(suffix)){
            if(local==null){
                local=new LocalFileStoreService(filesPath);
            }
            return local.delete(path,user);
        }
        if (StringUtil.isEmpty(path)) {
            Resp.fail("文件名不能为空");
        }
        if (user != null && path.indexOf("/" + user + "/") == -1) {
            Resp.fail("无权限");
        }
        String realPath=path.replaceFirst("^"+suffix,AliyunConfig.basePath.strValue());
        OSS ossClient=createClient();
        try {
            // 删除文件。
            ossClient.deleteObject(AliyunConfig.bucketName.strValue(), realPath);
        } catch (OSSException oe) {
            Resp.fail(oe.getMessage());
        } catch (ClientException ce) {
            Resp.fail(ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return Resp.ok();
    }

    @Override
    public ResponseEntity getFile(String path, String query) {
        if(!path.startsWith("/"+suffix)){
            if(local==null){
                local=new LocalFileStoreService(filesPath);
            }
            return local.getFile(path,query);
        }
        String realPath=path.replaceFirst("^/"+suffix,"");
        String url=AliyunConfig.domain.strValue()+AliyunConfig.basePath.strValue()+realPath;
        List<String> targetQuery=new ArrayList<>();

        if(StringUtil.isNotEmpty(query)){
            String[] params=query.split("&");
            for(String param:params){
                if(param.startsWith("_token=")){
                    continue;
                }
                targetQuery.add(param);
            }
            query=StringUtil.join(targetQuery,"&");
        }
        if(StringUtil.isNotEmpty(query)){
            if(query.indexOf("=")==-1){
                url+="?x-oss-process=style/"+query;
            }else{
                url+="?"+query;
            }
        }
        try {
            if(AliyunConfig.signed.value().asBoolean()){
                OSS ossClient=createClient();
                String targetPath=AliyunConfig.basePath.strValue()+realPath;
//                if(StringUtil.isNotEmpty(query)){
//                    if(query.indexOf("=")==-1){
//                        targetPath+="?x-oss-process=style/"+query;
//                    }else{
//                        targetPath+="?"+query;
//                    }
//                }
               // String uri= ossClient.generatePresignedUrl(AliyunConfig.bucketName.strValue(),targetPath, DateUtil.offsetMinute(new Date(),30)).toString();
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(AliyunConfig.bucketName.strValue(), targetPath);
                request.setExpiration(DateUtil.offsetMinute(new Date(),30));
                request.setMethod(HttpMethod.GET);
                //request.setQueryParameter();
                for(String q:targetQuery){
                    int idx=q.indexOf("=");
                    if(idx>0){
                        request.addQueryParameter(q.substring(0,idx),q.substring(idx+1));
                    }else{
                        request.addQueryParameter(q,"");
                    }
                }
                URI uri= ossClient.generatePresignedUrl(request).toURI();
                return ResponseEntity
                        .status(HttpStatus.TEMPORARY_REDIRECT)
                        .location(uri)
                        .build();
            }
            return ResponseEntity
                    .status(HttpStatus.TEMPORARY_REDIRECT)
                    .location(new URI(url))
                    .build();
        } catch (URISyntaxException e) {
            throw new BusinessException(e.getMessage());
        }
    }

    @Override
    public String getFullPath(String path, String prefix) {
        if(suffixMatcher.matcher(path).find()){
            String realPath=path.replaceFirst("^/?"+suffix,"");
            String url=AliyunConfig.domain.strValue()+AliyunConfig.basePath.strValue()+realPath;
            return url;
        }else if(fullPathMatcher.matcher(path).find()){
            return path;
        }
        return IFileStoreService.super.getFullPath(path, prefix);
    }

    @Override
    public List<FileInfo> list(String path) {
        return null;
    }

    public Map<String, String> policy(String fileName, String user){
        String extension = fileName;
        int idx = extension.lastIndexOf('.');
        if (idx > 0) {
            extension = extension.substring(idx);
        } else {
            extension = ".unknown";
        }
        String path=user+"/"+ IDUtil.getUUID()+extension;
        String host = "https://" + AliyunConfig.bucketName.strValue() + "." + AliyunConfig.endPoint.strValue().replaceFirst("^https?://","");
        String dir=AliyunConfig.basePath.strValue();
        OSS ossClient=createClient();


        long expireTime = 6000;
        long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
        Date expiration = new Date(expireEndTime);
        PolicyConditions policyConds = new PolicyConditions();
        policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
        policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY,dir );

        String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
        try {
            byte[]  binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);
            Map<String,String> respMap = new LinkedHashMap<String, String>();
            respMap.put("OSSAccessKeyId", AliyunConfig.accessKey.strValue());
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            respMap.put("key",path);
            respMap.put("path",suffix+path);
            return respMap;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
}
